package com.jiawa.train.business.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.Log;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.jiawa.train.business.domain.*;
import com.jiawa.train.business.domain.Req.ConfirmOrderDoReq;
import com.jiawa.train.business.domain.Req.ConfirmOrderQueryReq;
import com.jiawa.train.business.domain.Req.ConfirmOrderTicketReq;
import com.jiawa.train.business.domain.resp.ConfirmOrderQueryResp;
import com.jiawa.train.business.enums.ConfirmOrderStatusEnum;
import com.jiawa.train.business.enums.SeatColEnum;
import com.jiawa.train.business.enums.SeatTypeEnum;
import com.jiawa.train.business.mapper.ConfirmOrderMapper;
import com.jiawa.train.business.mapper.DailyTrainTicketMapper;
import com.jiawa.train.common.context.LoginMemberContext;
import com.jiawa.train.common.exception.BusinessException;
import com.jiawa.train.common.exception.BusinessExceptionEnum;
import com.jiawa.train.common.resp.PageResp;
import com.jiawa.train.common.util.SnowUtil;
import jakarta.validation.Valid;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.redisson.RedissonRedLock;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.MDC;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class ConfirmOrderService {

    @Autowired
    private ConfirmOrderMapper confirmOrderMapper;
    @Autowired
    private AfterConfirmOrderService afterConfirmOrderService;
    @Autowired
    private DailyTrainTicketService dailyTrainTicketService;
    @Autowired
    private DailyTrainTicketMapper dailyTrainTicketMapper;
    @Autowired
    private DailyTrainCarriageService dailyTrainCarriageService;
    @Autowired
    private DailyTrainSeatService dailyTrainSeatService;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    public PageResp<ConfirmOrderQueryResp> queryList(ConfirmOrderQueryReq confirmOrderQueryReq) {
        ConfirmOrderExample example = new ConfirmOrderExample();
        List<ConfirmOrder> confirmOrders = confirmOrderMapper.selectByExample(example);
        PageHelper.startPage(confirmOrderQueryReq.getPage(), confirmOrderQueryReq.getSize());

        List<ConfirmOrderQueryResp> orderList = BeanUtil.copyToList(confirmOrders, ConfirmOrderQueryResp.class);

        PageInfo<ConfirmOrder> pageInfo = new PageInfo<>(confirmOrders);
        PageResp<ConfirmOrderQueryResp> pageResp = new PageResp<>();
        pageResp.setTotal(pageInfo.getTotal());
        pageResp.setList(orderList);
        return pageResp;
    }

    /*@Transactional
    @SentinelResource(value = "doConfirm",blockHandler = "doConfirmBlock")
    public void doConfirm(ConfirmOrderDoReq confirmOrderDoReq) throws Exception {
        confirmOrderDoReq.setMemberId(LoginMemberContext.getId());
        // 使用redis分布式锁解决超卖问题
        // 日期+车次生成key
        String key = DateUtil.formatDate(confirmOrderDoReq.getDate()) + "-" + confirmOrderDoReq.getTrainCode();

        RLock lock = null;

        // 保存确认订单表
        try {
            lock = redissonClient.getLock(key);
            boolean tryLock = lock.tryLock(0, TimeUnit.SECONDS); // 看门狗机制

            if (tryLock) {
                System.out.println("恭喜，抢到锁");
            } else {
                System.out.println("没有抢到锁");
            }

            String reqJson = JSON.toJSONString(confirmOrderDoReq);
            rocketMQTemplate.convertAndSend("confirmOrder", reqJson);


            ConfirmOrder confirmOrder = new ConfirmOrder();
            confirmOrder.setMemberId(confirmOrderDoReq.getMemberId());
            confirmOrder.setTrainCode(confirmOrderDoReq.getTrainCode());
            confirmOrder.setDailyTrainTicketId(confirmOrderDoReq.getDailyTrainTicketId());
            confirmOrder.setId(SnowUtil.getSnowflakeNextId());
            confirmOrder.setCreateTime(new Date());
            confirmOrder.setUpdateTime(new Date());
            confirmOrder.setStatus(ConfirmOrderStatusEnum.INIT.getCode());
            confirmOrder.setTickets(JSON.toJSONString(confirmOrderDoReq.getTickets()));
            confirmOrder.setStart(confirmOrderDoReq.getStart());
            confirmOrder.setEnd(confirmOrderDoReq.getEnd());
            confirmOrder.setTrainCode(confirmOrderDoReq.getTrainCode());
            confirmOrder.setDate(confirmOrderDoReq.getDate());
            List<ConfirmOrderTicketReq> tickets = confirmOrderDoReq.getTickets();
            confirmOrder.setTickets(JSON.toJSONString(tickets));
            confirmOrderMapper.insert(confirmOrder);

            // 查出余票记录，需要得到真实的库存
            DailyTrainTicket dailyTrainTicket = dailyTrainTicketService.selectByUnique(confirmOrderDoReq.getTrainCode(), confirmOrderDoReq.getDate(), confirmOrderDoReq.getStart(), confirmOrderDoReq.getEnd());

            // 扣减余票数量，判断余票是否足够
            for (ConfirmOrderTicketReq confirmOrderTicketReq : confirmOrderDoReq.getTickets()) {
                String seatTypeCode = confirmOrderTicketReq.getSeatTypeCode();
                SeatTypeEnum seatTypeEnum = EnumUtil.getBy(SeatTypeEnum::getCode, seatTypeCode);
                switch (seatTypeEnum) {
                    case YDZ -> {
                        int count = dailyTrainTicket.getYdz() - 1;
                        if (count < 0) {
                            throw new BusinessException(BusinessExceptionEnum.BUSINESS_TRAIN_CODE_UNIQUE_ERROR);
                        }
                        dailyTrainTicket.setYdz(count);
                    }
                    case EDZ -> {
                        int count = dailyTrainTicket.getEdz() - 1;
                        if (count < 0) {
                            throw new BusinessException(BusinessExceptionEnum.BUSINESS_TRAIN_CODE_UNIQUE_ERROR);
                        }
                        dailyTrainTicket.setEdz(count);
                    }
                    case RW -> {
                        int count = dailyTrainTicket.getRw() - 1;
                        if (count < 0) {
                            throw new BusinessException(BusinessExceptionEnum.BUSINESS_TRAIN_CODE_UNIQUE_ERROR);
                        }
                        dailyTrainTicket.setRw(count);
                    }
                    case YW -> {
                        int count = dailyTrainTicket.getYw() - 1;
                        if (count < 0) {
                            throw new BusinessException(BusinessExceptionEnum.BUSINESS_TRAIN_CODE_UNIQUE_ERROR);
                        }
                        dailyTrainTicket.setYw(count);
                    }
                }
            }

            // 选座
            ConfirmOrderTicketReq ticketReq = tickets.get(0);
            List<DailyTrainSeat> finalSeatList = new ArrayList<>();
            if (StrUtil.isNotBlank(ticketReq.getSeat())) {
                System.out.println("本次购票有选座");
                List<SeatColEnum> colEnumList = SeatColEnum.getColsByType(ticketReq.getSeatTypeCode());
                System.out.println("本次选择的类型包含的列为：" + colEnumList);

                ArrayList<String> arrayList = new ArrayList<>();
                for (int i = 0; i <= 2; i++) {
                    for (SeatColEnum seatColEnum : colEnumList) {
                        arrayList.add(seatColEnum.getCode() + i);
                    }
                }
                ArrayList<Integer> offsetList = new ArrayList<>();
                for (ConfirmOrderTicketReq orderTicketReq : tickets) {
                    int index = arrayList.indexOf(orderTicketReq.getSeat());
                    offsetList.add(index);
                }

                // 修复：创建新列表存储计算结果
                List<Integer> newOffsets = offsetList.stream()
                        .map(index -> index - offsetList.get(0))
                        .collect(Collectors.toList());

                getSeat(finalSeatList, confirmOrderDoReq.getDate(), confirmOrderDoReq.getTrainCode(), ticketReq.getSeatTypeCode(), ticketReq.getSeat().split("")[0], newOffsets,
                        dailyTrainTicket.getStartIndex(), dailyTrainTicket.getEndIndex());

            } else {
                System.out.println("本次购票没有选座");
                for (ConfirmOrderTicketReq orderTicketReq : tickets) {
                    getSeat(
                            finalSeatList,
                            confirmOrderDoReq.getDate(),
                            confirmOrderDoReq.getTrainCode(),
                            orderTicketReq.getSeatTypeCode(),
                            null, null,
                            dailyTrainTicket.getStartIndex(),
                            dailyTrainTicket.getEndIndex());
                }
            }
            afterConfirmOrderService.afterConfirmOrder(null, finalSeatList);
        } finally {
            // 删除分布式锁
            if (null != lock && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }*/

    public void doConfirm(ConfirmOrderDoReq confirmOrderDoReq) throws Exception {
        confirmOrderDoReq.setMemberId(LoginMemberContext.getId());
        // 仅发送MQ消息，不执行业务逻辑
        confirmOrderDoReq.setLogId(MDC.get("LOG_ID"));
        String reqJson = JSON.toJSONString(confirmOrderDoReq);
        System.out.println("RocketMQ接收到的数据为：" + reqJson);
        rocketMQTemplate.convertAndSend("confirmOrder", reqJson);
    }


    @Transactional
    @SentinelResource(value = "doConfirm", blockHandler = "doConfirmBlock")
    public void processConfirmOrder(ConfirmOrderDoReq confirmOrderDoReq) throws Exception {
        // 保存确认订单表
        ConfirmOrder confirmOrder = new ConfirmOrder();
        confirmOrder.setMemberId(confirmOrderDoReq.getMemberId());
        confirmOrder.setTrainCode(confirmOrderDoReq.getTrainCode());
        confirmOrder.setDailyTrainTicketId(confirmOrderDoReq.getDailyTrainTicketId());
        confirmOrder.setId(SnowUtil.getSnowflakeNextId());
        confirmOrder.setCreateTime(new Date());
        confirmOrder.setUpdateTime(new Date());
        confirmOrder.setStatus(ConfirmOrderStatusEnum.INIT.getCode());
        confirmOrder.setTickets(JSON.toJSONString(confirmOrderDoReq.getTickets()));
        confirmOrder.setStart(confirmOrderDoReq.getStart());
        confirmOrder.setEnd(confirmOrderDoReq.getEnd());
        confirmOrder.setTrainCode(confirmOrderDoReq.getTrainCode());
        confirmOrder.setDate(confirmOrderDoReq.getDate());
        List<ConfirmOrderTicketReq> tickets = confirmOrderDoReq.getTickets();
        confirmOrder.setTickets(JSON.toJSONString(tickets));
        confirmOrderMapper.insert(confirmOrder);

        // 查出余票记录，需要得到真实的库存
        DailyTrainTicket dailyTrainTicket = dailyTrainTicketService.selectByUnique(
                confirmOrderDoReq.getTrainCode(),
                confirmOrderDoReq.getDate(),
                confirmOrderDoReq.getStart(),
                confirmOrderDoReq.getEnd()
        );

        // 扣减余票数量，判断余票是否足够
        for (ConfirmOrderTicketReq confirmOrderTicketReq : confirmOrderDoReq.getTickets()) {
            String seatTypeCode = confirmOrderTicketReq.getSeatTypeCode();
            SeatTypeEnum seatTypeEnum = EnumUtil.getBy(SeatTypeEnum::getCode, seatTypeCode);
            switch (seatTypeEnum) {
                case YDZ -> {
                    int count = dailyTrainTicket.getYdz() - 1;
                    if (count < 0) {
                        throw new BusinessException(BusinessExceptionEnum.BUSINESS_TRAIN_CODE_UNIQUE_ERROR);
                    }
                    dailyTrainTicket.setYdz(count);
                }
                case EDZ -> {
                    int count = dailyTrainTicket.getEdz() - 1;
                    if (count < 0) {
                        throw new BusinessException(BusinessExceptionEnum.BUSINESS_TRAIN_CODE_UNIQUE_ERROR);
                    }
                    dailyTrainTicket.setEdz(count);
                }
                case RW -> {
                    int count = dailyTrainTicket.getRw() - 1;
                    if (count < 0) {
                        throw new BusinessException(BusinessExceptionEnum.BUSINESS_TRAIN_CODE_UNIQUE_ERROR);
                    }
                    dailyTrainTicket.setRw(count);
                }
                case YW -> {
                    int count = dailyTrainTicket.getYw() - 1;
                    if (count < 0) {
                        throw new BusinessException(BusinessExceptionEnum.BUSINESS_TRAIN_CODE_UNIQUE_ERROR);
                    }
                    dailyTrainTicket.setYw(count);
                }
            }
        }

        // 更新余票数据
        dailyTrainTicketMapper.updateByPrimaryKey(dailyTrainTicket);

        // 选座
        List<DailyTrainSeat> finalSeatList = new ArrayList<>();
        ConfirmOrderTicketReq ticketReq = tickets.get(0);
        if (StrUtil.isNotBlank(ticketReq.getSeat())) {
            System.out.println("本次购票有选座");
            List<SeatColEnum> colEnumList = SeatColEnum.getColsByType(ticketReq.getSeatTypeCode());
            System.out.println("本次选择的类型包含的列为：" + colEnumList);

            ArrayList<String> arrayList = new ArrayList<>();
            for (int i = 0; i <= 2; i++) {
                for (SeatColEnum seatColEnum : colEnumList) {
                    arrayList.add(seatColEnum.getCode() + i);
                }
            }
            ArrayList<Integer> offsetList = new ArrayList<>();
            for (ConfirmOrderTicketReq orderTicketReq : tickets) {
                int index = arrayList.indexOf(orderTicketReq.getSeat());
                offsetList.add(index);
            }

            // 计算偏移量
            List<Integer> newOffsets = offsetList.stream()
                    .map(index -> index - offsetList.get(0))
                    .collect(Collectors.toList());

            getSeat(
                    finalSeatList,
                    confirmOrderDoReq.getDate(),
                    confirmOrderDoReq.getTrainCode(),
                    ticketReq.getSeatTypeCode(),
                    ticketReq.getSeat().split("")[0],
                    newOffsets,
                    dailyTrainTicket.getStartIndex(),
                    dailyTrainTicket.getEndIndex()
            );
        } else {
            System.out.println("本次购票没有选座");
            for (ConfirmOrderTicketReq orderTicketReq : tickets) {
                getSeat(
                        finalSeatList,
                        confirmOrderDoReq.getDate(),
                        confirmOrderDoReq.getTrainCode(),
                        orderTicketReq.getSeatTypeCode(),
                        null,
                        null,
                        dailyTrainTicket.getStartIndex(),
                        dailyTrainTicket.getEndIndex()
                );
            }
        }

        // 更新座位状态
        for (DailyTrainSeat seat : finalSeatList) {
            dailyTrainSeatService.update(seat);
        }

        // 修复：传递正确的参数（dailyTrainTicket 而不是 confirmOrder）
        afterConfirmOrderService.afterConfirmOrder(dailyTrainTicket, finalSeatList);
    }

    public void getSeat(List<DailyTrainSeat> finalSeatList, Date date, String trainCode, String seatType, String column, List<Integer> offsetList, Integer startIndex, Integer endIndex) {
        ArrayList<DailyTrainSeat> getSeatList = new ArrayList<>();
        List<DailyTrainCarriage> carriageList = dailyTrainCarriageService.selectByTrainCode(date, trainCode, seatType);
        System.out.println("共查出符合条件的车厢数量为：" + carriageList.size());

        boolean alreadyChooseFlag = false;
        for (DailyTrainCarriage carriage : carriageList) {
            System.out.println(carriage.getIndex());
            List<DailyTrainSeat> seatList = dailyTrainSeatService.querySeat(date, trainCode, carriage.getIndex());

            for (int i = 0; i < seatList.size(); i++) {
                DailyTrainSeat dailyTrainSeat = seatList.get(i);
                String col = dailyTrainSeat.getCol();
                Integer seatIndex = dailyTrainSeat.getCarriageSeatIndex();

                // 判断当前座位不能被选中
                for (DailyTrainSeat finalSeat : finalSeatList) {
                    if (finalSeat.getId().equals(dailyTrainSeat.getId())) {
                        alreadyChooseFlag = true;
                        break;
                    }
                }

                if (alreadyChooseFlag) {
                    System.out.println("座位已被选中，查看下一个座位");
                    continue;
                }

                if (StrUtil.isBlank(column)) {

                } else {
                    if (!column.equals(col)) {

                    }
                }

                boolean isChoose = calSell(dailyTrainSeat, startIndex, endIndex);
                if (isChoose) {
                    getSeatList.add(dailyTrainSeat);
                    System.out.println("以选中座位");
                } else {
                    System.out.println("未选中座位");
                }

                boolean isGetAllOffsetSeat = true;

                if (CollUtil.isNotEmpty(offsetList)) {
                    System.out.println("有偏移值：" + offsetList);
                    // 从索引1开始，索引0未已选中的票
                    for (int j = 1; j < offsetList.size(); j++) {
                        Integer offset = offsetList.get(j);
                        int nextIndex = i + offset;

                        if (nextIndex >= seatList.size()) {
                            System.out.println("选座失败");
                            isGetAllOffsetSeat = false;
                            break;
                        }

                        DailyTrainSeat nextDailyTrainSeat = seatList.get(nextIndex);
                        boolean isChooseNext = calSell(nextDailyTrainSeat, startIndex, endIndex);
                        if (isChooseNext) {
                            getSeatList.add(nextDailyTrainSeat);
                            System.out.println("以选中座位");
                        } else {
                            isGetAllOffsetSeat = false;
                            System.out.println("未选中座位");
                        }
                    }
                }

                if (!isGetAllOffsetSeat) {
                    continue;
                }

                // 保存选好的座位
                finalSeatList.addAll(getSeatList);
                return;

            }
        }
    }

    public boolean calSell(DailyTrainSeat trainSeat, Integer startIndex, Integer endIndex) {
        String sell = trainSeat.getSell();

        // 添加边界检查
        if (sell == null || sell.length() < endIndex) {
            return false;
        }

        String sellPart = sell.substring(startIndex, endIndex);
        if (Integer.parseInt(sellPart) > 0) {
            return false;
        } else {
            String curSell = sellPart.replace('0', '1');
            curSell = StrUtil.fillBefore(curSell, '0', endIndex);
            curSell = StrUtil.fillAfter(curSell, '1', sell.length());
            int newSellInt = NumberUtil.binaryToInt(curSell) | NumberUtil.binaryToInt(sell);
            String newSell = NumberUtil.getBinaryStr(newSellInt);
            newSell = StrUtil.fillBefore(newSell, '0', sell.length());
            trainSeat.setSell(newSell);
            return true;
        }
    }

    /**
     * 降级方法
     * @param confirmOrderDoReq
     * @param e
     */
    public void doConfirmBlock(ConfirmOrderDoReq confirmOrderDoReq, BlockException e){
        throw new BusinessException(BusinessExceptionEnum.BUSINESS_TRAIN_CODE_UNIQUE_ERROR);
    }
}